
---- Copyright (c) 2014-2017 cocos2dx开源
---- 迷你创想 - 海马

---- cocos2dx的class面向对象实现函数
---- 不一定需要使用到这里来实现类继承，其他技术手段也能实现同样的效果

--- 例子:
---  ns_class  = require("modules.commhm.class_cocos");
---  CFather = ns_class.class("CFatherName")            --父类
---  CChild  = ns_class.class("CChildName", CFather)    --子类

--- 已知问题： 不同子类A B C都继承于父类F，
--- 子类调用父类F中的方法修改父类的变量，会发现父类其实是共享一个obj的。


local type = type
local pairs = pairs
local ipairs = ipairs
local assert = assert
local string = string
local string_format = string.format
local setmetatable = setmetatable
local getmetatable = getmetatable
local error = error

local FOO = {
    _VERSION = '0.12.1';
}


--- 新建一个类
function FOO.class(classname, ...)
    local cls = {__cname = classname}

    local supers = {...}
    for _, super in ipairs(supers) do
        local superType = type(super)
        assert(superType == "nil" or superType == "table" or superType == "function",
                string.format("class() - create class \"%s\" with invalid super class type \"%s\"",
                        classname, superType))

        if superType == "function" then
            assert(cls.__create == nil,
                    string.format("class() - create class \"%s\" with more than one creating function",
                            classname));
            -- if super is function, set it to __create
            cls.__create = super
        elseif superType == "table" then
            if super[".isclass"] then
                -- super is native class
                assert(cls.__create == nil,
                        string.format("class() - create class \"%s\" with more than one creating function or native class",
                                classname));
                cls.__create = function() return super:create() end
            else
                -- super is pure lua class
                cls.__supers = cls.__supers or {}
                cls.__supers[#cls.__supers + 1] = super
                if not cls.super then
                    -- set first super pure lua class as class.super
                    cls.super = super
                end
            end
        else
            error(string.format("class() - create class \"%s\" with invalid super type",
                    classname), 0)
        end
    end

    cls.__index = cls
    if not cls.__supers or #cls.__supers == 1 then
        setmetatable(cls, {__index = cls.super})
    else
        setmetatable(cls, {__index = function(_, key)
            local supers = cls.__supers
            for i = 1, #supers do
                local super = supers[i]
                if super[key] then return super[key] end
            end
        end})
    end

    if not cls.ctor then
        -- add default constructor
        cls.ctor = function() end
    end
    cls.new = function(...)
        local instance
        if cls.__create then
            instance = cls.__create(...)
        else
            instance = {}
        end
        FOO.setmetatableindex(instance, cls)
        instance.class = cls
        instance:ctor(...)
        return instance
    end
    cls.create = function(_, ...)
        return cls.new(...)
    end

    return cls
end


---- 为传入的t(table)设置metatable, 用来实现方法查找
FOO.setmetatableindex = function(t, index)
    if  type(t) == "userdata" then
        -- 没必要支持 userdata, 避免风险
        error( 'create class using userdata' )
        --local peer = tolua.getpeer(t)
        --if not peer then
            --peer = {}
            --tolua.setpeer(t, peer)
        --end
        --FOO.setmetatableindex(peer, index)
    else
        local mt = getmetatable(t)
        if not mt then mt = {} end
        if not mt.__index then
            mt.__index = index
            setmetatable(t, mt)
        elseif mt.__index ~= index then
            FOO.setmetatableindex(mt, index)
        end
    end
end


---- 深度克隆一个obj  ( 老版本的 FOO.class 会使用到，目前不会使用到这个函数 )
---- 除了基本类型，metatable也会复制
function FOO.clone(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local newObject = {}
        lookup_table[object] = newObject
        for key, value in pairs(object) do
            newObject[_copy(key)] = _copy(value)
        end
        return setmetatable(newObject, getmetatable(object))
    end
    return _copy(object)
end


return FOO